/************************************************************************************
* 
* Wavechild670 v0.1 
* 
* wdfcircuits.h
* 
* By Peter Raffensperger 11 March 2014
* 
* Reference:
* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012). 
* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12), 
* York, UK, September 17-21, 2012.
* 
* Note:
* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or 
* affiliated with the author.
* 
* License:
* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
* software in an academic context, we would appreciate it if you referenced the original
* paper.
* 
************************************************************************************/



//Autogenerated wave digital filter circuits
//Peter Raffensperger
#ifndef WDFCIRCUITS_H
#define WDFCIRCUITS_H
#include "generatedwdfutilities.h"
#include "scope.h"

// AUTOGENERATED Wave digital filter 2012-03-14 15:24:51.084121
// Advanced Machine Audio Python WDF Generator 
// Peter Raffensperger, 2012
class TubeStageCircuit {
	/*Circuit schematic: (B = winding symbol)
	         VplateSource
	          |
	          Rplate                      Primary  Secondary
	          |                            Np  :   Ns
	          --------Lp---Rp--------------B       B------Rs----Ls------------------------
	                           |   |       B       B               |         |           |
	                           Rc  Lm      B TXFMR B               Cw      Routput   Rsidechain
	                           |   |       B       B               |         |           |
	          -----------------------------B       B--------------------------------------
	          |
	Vgate --Tube
	          |
	        -----------------
	        |               |
	        Rcathode        Ccathode
	        |               |
	       VcathodeSource   cathodeCapacitorConn
	*/
public:
	TubeStageCircuit(Real C_Ccathode, Real C_Cw, Real E_VcathodeBias, Real E_Vplate, Real L_Lm, Real L_Lp, Real L_Ls, Real NpOverNs, Real R_Rc, Real R_Routput, Real R_Rp, Real R_Rs, Real R_Rsidechain, Real R_VcathodeBias, Real R_Vplate, Real R_cathodeCapacitorConn, BidirectionalUnitDelayInterface* cathodeCapacitorConn_, Real sampleRate, WDFTubeInterface& tube_) : tube(tube_){
		updateRValues(C_Ccathode, C_Cw, E_VcathodeBias, E_Vplate, L_Lm, L_Lp, L_Ls, NpOverNs, R_Rc, R_Routput, R_Rp, R_Rs, R_Rsidechain, R_VcathodeBias, R_Vplate, R_cathodeCapacitorConn, cathodeCapacitorConn_, sampleRate);
		Ccathodea = 0.0;
		Lpa = 0.0;
		Lma = 0.0;
		Lsa = 0.0;
		Cwa = 0.0;
		Vcathode = 0.0;
	}

	void updateRValues(Real C_Ccathode, Real C_Cw, Real E_VcathodeBias, Real E_Vplate, Real L_Lm, Real L_Lp, Real L_Ls, Real NpOverNs, Real R_Rc, Real R_Routput, Real R_Rp, Real R_Rs, Real R_Rsidechain, Real R_VcathodeBias, Real R_Vplate, Real R_cathodeCapacitorConn, BidirectionalUnitDelayInterface* cathodeCapacitorConn_, Real sampleRate){
		Real VcathodeBiasR = R_VcathodeBias;
		VcathodeBiasE = E_VcathodeBias;
		Real CcathodeR = 1.0 / (2.0*C_Ccathode*sampleRate);
		Real VplateR = R_Vplate;
		VplateE = E_Vplate;
		Real RoutputR = R_Routput;
		Real RsidechainR = R_Rsidechain;
		Real outputParallelConn_1R = RoutputR;
		Real outputParallelConn_2R = RsidechainR;
		Real outputParallelConn_3R = 1.0 /(1.0 / outputParallelConn_1R + 1.0 / outputParallelConn_2R);
		outputParallelConn_3Gamma1 = 1.0 / outputParallelConn_1R/(1.0 / outputParallelConn_1R + 1.0 / outputParallelConn_2R);
		Assert(outputParallelConn_3Gamma1 >= 0.0 && outputParallelConn_3Gamma1 <= 1.0);
		Real LpR = 2.0*L_Lp*sampleRate;
		Real RpR = R_Rp;
		Real LmR = 2.0*L_Lm*sampleRate;
		Real RcR = R_Rc;
		Real LsR = 2.0*L_Ls*sampleRate;
		Real RsR = R_Rs;
		Real CwR = 1.0 / (2.0*C_Cw*sampleRate);
		transformern = 1.0 / NpOverNs;
		transformerOneOvern = NpOverNs;
		Real secondaryOutputParallelConn_1R = outputParallelConn_3R;
		Real secondaryOutputParallelConn_2R = CwR;
		Real secondaryOutputParallelConn_3R = 1.0 /(1.0 / secondaryOutputParallelConn_1R + 1.0 / secondaryOutputParallelConn_2R);
		secondaryOutputParallelConn_3Gamma1 = 1.0 / secondaryOutputParallelConn_1R/(1.0 / secondaryOutputParallelConn_1R + 1.0 / secondaryOutputParallelConn_2R);
		Assert(secondaryOutputParallelConn_3Gamma1 >= 0.0 && secondaryOutputParallelConn_3Gamma1 <= 1.0);
		Real secondarySeriesConn2_3R = (RsR + LsR);
		secondarySeriesConn2_3Gamma1 = RsR/(RsR + LsR);
		Assert(secondarySeriesConn2_3Gamma1 >= 0.0 && secondarySeriesConn2_3Gamma1 <= 1.0);
		secondarySeriesConn1_3Gamma1 = secondaryOutputParallelConn_3R/(secondaryOutputParallelConn_3R + secondarySeriesConn2_3R);
		Assert(secondarySeriesConn1_3Gamma1 >= 0.0 && secondarySeriesConn1_3Gamma1 <= 1.0);
		Real transformerR = (secondaryOutputParallelConn_3R + secondarySeriesConn2_3R)/(transformern*transformern);
		Real primaryParallelConn1_1R = transformerR;
		Real primarySeriesConn2_3R = (LpR + RpR);
		primarySeriesConn2_3Gamma1 = LpR/(LpR + RpR);
		Assert(primarySeriesConn2_3Gamma1 >= 0.0 && primarySeriesConn2_3Gamma1 <= 1.0);
		Real primaryParallelConn2_1R = LmR;
		Real primaryParallelConn2_2R = RcR;
		Real primaryParallelConn2_3R = 1.0 /(1.0 / primaryParallelConn2_1R + 1.0 / primaryParallelConn2_2R);
		primaryParallelConn2_3Gamma1 = 1.0 / primaryParallelConn2_1R/(1.0 / primaryParallelConn2_1R + 1.0 / primaryParallelConn2_2R);
		Assert(primaryParallelConn2_3Gamma1 >= 0.0 && primaryParallelConn2_3Gamma1 <= 1.0);
		Real primaryParallelConn1_2R = primaryParallelConn2_3R;
		Real primaryParallelConn1_3R = 1.0 /(1.0 / primaryParallelConn1_1R + 1.0 / primaryParallelConn1_2R);
		primaryParallelConn1_3Gamma1 = 1.0 / primaryParallelConn1_1R/(1.0 / primaryParallelConn1_1R + 1.0 / primaryParallelConn1_2R);
		Assert(primaryParallelConn1_3Gamma1 >= 0.0 && primaryParallelConn1_3Gamma1 <= 1.0);
		Real primaryInputSeriesConn_3R = (primarySeriesConn2_3R + primaryParallelConn1_3R);
		primaryInputSeriesConn_3Gamma1 = primarySeriesConn2_3R/(primarySeriesConn2_3R + primaryParallelConn1_3R);
		Assert(primaryInputSeriesConn_3Gamma1 >= 0.0 && primaryInputSeriesConn_3Gamma1 <= 1.0);
		Real cathodeCapacitorConnR = R_cathodeCapacitorConn;
		Real cathodeCapSeriesConn_3R = (CcathodeR + cathodeCapacitorConnR);
		cathodeCapSeriesConn_3Gamma1 = CcathodeR/(CcathodeR + cathodeCapacitorConnR);
		Assert(cathodeCapSeriesConn_3Gamma1 >= 0.0 && cathodeCapSeriesConn_3Gamma1 <= 1.0);
		Real cathodeParallelConn_1R = VcathodeBiasR;
		Real cathodeParallelConn_2R = cathodeCapSeriesConn_3R;
		Real cathodeParallelConn_3R = 1.0 /(1.0 / cathodeParallelConn_1R + 1.0 / cathodeParallelConn_2R);
		cathodeParallelConn_3Gamma1 = 1.0 / cathodeParallelConn_1R/(1.0 / cathodeParallelConn_1R + 1.0 / cathodeParallelConn_2R);
		Assert(cathodeParallelConn_3Gamma1 >= 0.0 && cathodeParallelConn_3Gamma1 <= 1.0);
		Real tubeSeriesConn1_3R = (primaryInputSeriesConn_3R + VplateR);
		tubeSeriesConn1_3Gamma1 = primaryInputSeriesConn_3R/(primaryInputSeriesConn_3R + VplateR);
		Assert(tubeSeriesConn1_3Gamma1 >= 0.0 && tubeSeriesConn1_3Gamma1 <= 1.0);
		Real tubeSeriesConn2_3R = (tubeSeriesConn1_3R + cathodeParallelConn_3R);
		tubeSeriesConn2_3Gamma1 = tubeSeriesConn1_3R/(tubeSeriesConn1_3R + cathodeParallelConn_3R);
		Assert(tubeSeriesConn2_3Gamma1 >= 0.0 && tubeSeriesConn2_3Gamma1 <= 1.0);
		cathodeCapacitorConn = cathodeCapacitorConn_;
		tubeR = tubeSeriesConn2_3R;
		LOG_INFO(" ");
		LOG_INFO("outputParallelConn_3Gamma1=" << outputParallelConn_3Gamma1);
		LOG_INFO("cathodeCapSeriesConn_3Gamma1=" << cathodeCapSeriesConn_3Gamma1);
		LOG_INFO("cathodeParallelConn_3Gamma1=" << cathodeParallelConn_3Gamma1);
		LOG_INFO("tubeSeriesConn1_3Gamma1=" << tubeSeriesConn1_3Gamma1);
		LOG_INFO("tubeSeriesConn2_3Gamma1=" << tubeSeriesConn2_3Gamma1);
		LOG_INFO(" ");
		LOG_INFO("primarySeriesConn2_3Gamma1=" << primarySeriesConn2_3Gamma1);
		LOG_INFO("secondarySeriesConn2_3Gamma1=" << secondarySeriesConn2_3Gamma1);
		LOG_INFO("primaryInputSeriesConn_3Gamma1=" << primaryInputSeriesConn_3Gamma1);
		LOG_INFO("secondaryOutputParallelConn_3Gamma1=" << secondaryOutputParallelConn_3Gamma1);
		LOG_INFO("secondarySeriesConn1_3Gamma1=" << secondarySeriesConn1_3Gamma1);
		LOG_INFO("primaryParallelConn2_3Gamma1=" << primaryParallelConn2_3Gamma1);
		LOG_INFO("primaryParallelConn1_3Gamma1=" << primaryParallelConn1_3Gamma1);
	}

	Real advance(Real vgate){
		//Get Bs
		//tubeSeriesConn2_3GetB
		//tubeSeriesConn1_3GetB
		//primaryInputSeriesConn_3GetB
		//primarySeriesConn2_3GetB
		Real Lpb = -Lpa;
		//primarySeriesConn2_1SetA
		//RpGetB
		//primarySeriesConn2_2SetA
		Real primarySeriesConn2_3b3 = -(Lpb);
		//primaryInputSeriesConn_1SetA
		//primaryParallelConn1_3GetB
		//transformerGetB
		//secondarySeriesConn1_3GetB
		//secondaryOutputParallelConn_3GetB
		//outputParallelConn_3GetB
		//RoutputGetB
		//outputParallelConn_1SetA
		//RsidechainGetB
		//outputParallelConn_2SetA
		Real outputParallelConn_3b3 = -outputParallelConn_3Gamma1*(0.0);
		//secondaryOutputParallelConn_1SetA
		Real Cwb = Cwa;
		//secondaryOutputParallelConn_2SetA
		Real secondaryOutputParallelConn_3b3 = Cwb - secondaryOutputParallelConn_3Gamma1*(Cwb - outputParallelConn_3b3);
		//secondarySeriesConn1_1SetA
		//secondarySeriesConn2_3GetB
		//RsGetB
		//secondarySeriesConn2_1SetA
		Real Lsb = -Lsa;
		//secondarySeriesConn2_2SetA
		Real secondarySeriesConn2_3b3 = -(Lsb);
		//secondarySeriesConn1_2SetA
		Real secondarySeriesConn1_3b3 = -(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3);
		//primaryParallelConn1_1SetA
		//primaryParallelConn2_3GetB
		Real Lmb = -Lma;
		//primaryParallelConn2_1SetA
		//RcGetB
		//primaryParallelConn2_2SetA
		Real primaryParallelConn2_3b3 = -primaryParallelConn2_3Gamma1*(-Lmb);
		//primaryParallelConn1_2SetA
		Real primaryParallelConn1_3b3 = primaryParallelConn2_3b3 - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
		//primaryInputSeriesConn_2SetA
		Real primaryInputSeriesConn_3b3 = -(primarySeriesConn2_3b3 + primaryParallelConn1_3b3);
		//tubeSeriesConn1_1SetA
		//VplateGetB
		//tubeSeriesConn1_2SetA
		Real tubeSeriesConn1_3b3 = -(primaryInputSeriesConn_3b3 + VplateE);
		//tubeSeriesConn2_1SetA
		//cathodeParallelConn_3GetB
		//VcathodeBiasGetB
		//cathodeParallelConn_1SetA
		//cathodeCapSeriesConn_3GetB
		Real Ccathodeb = Ccathodea;
		//cathodeCapSeriesConn_1SetA
		//cathodeCapacitorConnGetB
		//cathodeCapSeriesConn_2SetA
		Real cathodeCapSeriesConn_3b3 = -(Ccathodeb + cathodeCapacitorConn->getB());
		//cathodeParallelConn_2SetA
		Real cathodeParallelConn_3b3 = cathodeCapSeriesConn_3b3 - cathodeParallelConn_3Gamma1*(cathodeCapSeriesConn_3b3 - VcathodeBiasE);
		//tubeSeriesConn2_2SetA
		Real tubeSeriesConn2_3b3 = -(tubeSeriesConn1_3b3 + cathodeParallelConn_3b3);
		//Call tube model
		Real b = tube.getB(tubeSeriesConn2_3b3, tubeR, vgate, Vcathode);
		SCOPE("Vak", -(tubeSeriesConn2_3b3 + b));
		SCOPE("VplateE", VplateE);
		//Set As
		//tubeSeriesConn2_3SetA
		Real tubeSeriesConn2_3b1 = tubeSeriesConn1_3b3 - tubeSeriesConn2_3Gamma1*(tubeSeriesConn1_3b3 + cathodeParallelConn_3b3 + b);
		//tubeSeriesConn1_3SetA
		Real tubeSeriesConn1_3b1 = primaryInputSeriesConn_3b3 - tubeSeriesConn1_3Gamma1*(primaryInputSeriesConn_3b3 + VplateE + tubeSeriesConn2_3b1);
		//primaryInputSeriesConn_3SetA
		Real primaryInputSeriesConn_3b1 = primarySeriesConn2_3b3 - primaryInputSeriesConn_3Gamma1*(primarySeriesConn2_3b3 + primaryParallelConn1_3b3 + tubeSeriesConn1_3b1);
		//primarySeriesConn2_3SetA
		Real primarySeriesConn2_3b1 = Lpb - primarySeriesConn2_3Gamma1*(Lpb + primaryInputSeriesConn_3b1);
		Lpa = primarySeriesConn2_3b1;
		//RpSetA
		Real primaryInputSeriesConn_3b2 = -(primarySeriesConn2_3b3 + tubeSeriesConn1_3b1 - primaryInputSeriesConn_3Gamma1*(primarySeriesConn2_3b3 + primaryParallelConn1_3b3 + tubeSeriesConn1_3b1));
		//primaryParallelConn1_3SetA
		Real primaryParallelConn1_3b1 = primaryInputSeriesConn_3b2 + primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
		//transformerSetA
		//secondarySeriesConn1_3SetA
		Real secondarySeriesConn1_3b1 = secondaryOutputParallelConn_3b3 - secondarySeriesConn1_3Gamma1*(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3 + primaryParallelConn1_3b1*transformern);
		//secondaryOutputParallelConn_3SetA
		//outputParallelConn_3SetA
		//RoutputSetA
		//RsidechainSetA
		Real secondaryOutputParallelConn_3b2 = secondarySeriesConn1_3b1 - secondaryOutputParallelConn_3Gamma1*(Cwb - outputParallelConn_3b3);
		Cwa = secondaryOutputParallelConn_3b2;
		Real secondarySeriesConn1_3b2 = -(secondaryOutputParallelConn_3b3 + primaryParallelConn1_3b1*transformern - secondarySeriesConn1_3Gamma1*(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3 + primaryParallelConn1_3b1*transformern));
		//secondarySeriesConn2_3SetA
		//RsSetA
		Real secondarySeriesConn2_3b2 = -(secondarySeriesConn1_3b2 - secondarySeriesConn2_3Gamma1*(Lsb + secondarySeriesConn1_3b2));
		Lsa = secondarySeriesConn2_3b2;
		Real primaryParallelConn1_3b2 = primaryInputSeriesConn_3b2 - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
		//primaryParallelConn2_3SetA
		Real primaryParallelConn2_3b1 = primaryParallelConn1_3b2  - Lmb - primaryParallelConn2_3Gamma1*(-Lmb);
		Lma = primaryParallelConn2_3b1;
		//RcSetA
		Real tubeSeriesConn2_3b2 = -(tubeSeriesConn1_3b3 + b - tubeSeriesConn2_3Gamma1*(tubeSeriesConn1_3b3 + cathodeParallelConn_3b3 + b));
		//cathodeParallelConn_3SetA
		Real cathodeParallelConn_3b2 = tubeSeriesConn2_3b2 - cathodeParallelConn_3Gamma1*(cathodeCapSeriesConn_3b3 - VcathodeBiasE);
		//cathodeCapSeriesConn_3SetA
		Real cathodeCapSeriesConn_3b1 = Ccathodeb - cathodeCapSeriesConn_3Gamma1*(Ccathodeb + cathodeCapacitorConn->getB() + cathodeParallelConn_3b2);
		Ccathodea = cathodeCapSeriesConn_3b1;
		Real cathodeCapSeriesConn_3b2 = -(Ccathodeb + cathodeParallelConn_3b2 - cathodeCapSeriesConn_3Gamma1*(Ccathodeb + cathodeCapacitorConn->getB() + cathodeParallelConn_3b2));
		//cathodeCapacitorConnSetA
		Real cathodeCapacitorConna = cathodeCapSeriesConn_3b2;
		cathodeCapacitorConn->setA(cathodeCapacitorConna);
		Vcathode = -(Ccathodea + Ccathodeb);
		SCOPE("Vcathode", Vcathode);
		SCOPE("Va", -(tubeSeriesConn2_3b3 + b) + Vcathode);
		return -(Cwa + Cwb);
	}

	vector<Real> getState(){
		vector<Real> state(6, 0.0);
		state[0] = Ccathodea;
		state[1] = Lpa;
		state[2] = Lma;
		state[3] = Lsa;
		state[4] = Cwa;
		state[5] = Vcathode;
		return state;
	}
	void setState(vector<Real> state) {
		Assert(state.size() == 6);
		Ccathodea = state[0];
		Lpa = state[1];
		Lma = state[2];
		Lsa = state[3];
		Cwa = state[4];
		Vcathode = state[5];
	}
private:
	//State variables
	Real Ccathodea;
	Real Lpa;
	Real Lma;
	Real Lsa;
	Real Cwa;
	Real Vcathode;

	//R values
	Real outputParallelConn_3Gamma1;
	BidirectionalUnitDelayInterface* cathodeCapacitorConn;
	Real primarySeriesConn2_3Gamma1;
	Real cathodeCapSeriesConn_3Gamma1;
	Real tubeSeriesConn1_3Gamma1;
	Real VplateE;
	Real secondarySeriesConn2_3Gamma1;
	Real primaryInputSeriesConn_3Gamma1;
	Real secondaryOutputParallelConn_3Gamma1;
	Real cathodeParallelConn_3Gamma1;
	Real secondarySeriesConn1_3Gamma1;
	Real transformerOneOvern;
	Real transformern;
	Real VcathodeBiasE;
	Real tubeSeriesConn2_3Gamma1;
	Real primaryParallelConn2_3Gamma1;
	Real primaryParallelConn1_3Gamma1;
	Real tubeR;
	//Extra members
	WDFTubeInterface tube;
};



// AUTOGENERATED Wave digital filter 2012-03-14 15:24:51.132756
// Advanced Machine Audio Python WDF Generator 
// Peter Raffensperger, 2012
class TransformerCoupledInputCircuit {
	/*Circuit schematic:
	                                Primary  Secondary
	                                    Np  :   Ns
	 ----Rin-------Lp---Rp--------------B       B------Rs----Ls------------
	 |         |            |   |       B       B               |         |
	Vin     RinTerm         Rc  Lm      B TXFMR B               Cw      Rload
	 |         |            |   |       B       B               |         |
	 -----------------------------------B       B--------------------------
	B = winding symbol
	*/
public:
	TransformerCoupledInputCircuit(Real C_Cw, Real E_inputSource, Real L_Lm, Real L_Lp, Real L_Ls, Real NpOverNs, Real R_Rc, Real R_RinputTermination, Real R_Rload, Real R_Rp, Real R_Rs, Real R_inputSource, Real sampleRate){
		updateRValues(C_Cw, E_inputSource, L_Lm, L_Lp, L_Ls, NpOverNs, R_Rc, R_RinputTermination, R_Rload, R_Rp, R_Rs, R_inputSource, sampleRate);
		Lpa = 0.0;
		Lma = 0.0;
		Lsa = 0.0;
		Cwa = 0.0;
	}

	void updateRValues(Real C_Cw, Real E_inputSource, Real L_Lm, Real L_Lp, Real L_Ls, Real NpOverNs, Real R_Rc, Real R_RinputTermination, Real R_Rload, Real R_Rp, Real R_Rs, Real R_inputSource, Real sampleRate){
		Real RloadR = R_Rload;
		Real inputSourceR = R_inputSource;
		inputSourceE = E_inputSource;
		Real RinputTerminationR = R_RinputTermination;
		Real LpR = 2.0*L_Lp*sampleRate;
		Real RpR = R_Rp;
		Real LmR = 2.0*L_Lm*sampleRate;
		Real RcR = R_Rc;
		Real LsR = 2.0*L_Ls*sampleRate;
		Real RsR = R_Rs;
		Real CwR = 1.0 / (2.0*C_Cw*sampleRate);
		transformern = 1.0 / NpOverNs;
		transformerOneOvern = NpOverNs;
		Real secondaryOutputParallelConn_1R = RloadR;
		Real secondaryOutputParallelConn_2R = CwR;
		Real secondaryOutputParallelConn_3R = 1.0 /(1.0 / secondaryOutputParallelConn_1R + 1.0 / secondaryOutputParallelConn_2R);
		secondaryOutputParallelConn_3Gamma1 = 1.0 / secondaryOutputParallelConn_1R/(1.0 / secondaryOutputParallelConn_1R + 1.0 / secondaryOutputParallelConn_2R);
		Assert(secondaryOutputParallelConn_3Gamma1 >= 0.0 && secondaryOutputParallelConn_3Gamma1 <= 1.0);
		Real secondarySeriesConn2_3R = (RsR + LsR);
		secondarySeriesConn2_3Gamma1 = RsR/(RsR + LsR);
		Assert(secondarySeriesConn2_3Gamma1 >= 0.0 && secondarySeriesConn2_3Gamma1 <= 1.0);
		secondarySeriesConn1_3Gamma1 = secondaryOutputParallelConn_3R/(secondaryOutputParallelConn_3R + secondarySeriesConn2_3R);
		Assert(secondarySeriesConn1_3Gamma1 >= 0.0 && secondarySeriesConn1_3Gamma1 <= 1.0);
		Real transformerR = (secondaryOutputParallelConn_3R + secondarySeriesConn2_3R)/(transformern*transformern);
		Real primaryParallelConn1_1R = transformerR;
		Real primarySeriesConn2_3R = (LpR + RpR);
		primarySeriesConn2_3Gamma1 = LpR/(LpR + RpR);
		Assert(primarySeriesConn2_3Gamma1 >= 0.0 && primarySeriesConn2_3Gamma1 <= 1.0);
		Real primaryParallelConn2_1R = LmR;
		Real primaryParallelConn2_2R = RcR;
		Real primaryParallelConn2_3R = 1.0 /(1.0 / primaryParallelConn2_1R + 1.0 / primaryParallelConn2_2R);
		primaryParallelConn2_3Gamma1 = 1.0 / primaryParallelConn2_1R/(1.0 / primaryParallelConn2_1R + 1.0 / primaryParallelConn2_2R);
		Assert(primaryParallelConn2_3Gamma1 >= 0.0 && primaryParallelConn2_3Gamma1 <= 1.0);
		Real primaryParallelConn1_2R = primaryParallelConn2_3R;
		Real primaryParallelConn1_3R = 1.0 /(1.0 / primaryParallelConn1_1R + 1.0 / primaryParallelConn1_2R);
		primaryParallelConn1_3Gamma1 = 1.0 / primaryParallelConn1_1R/(1.0 / primaryParallelConn1_1R + 1.0 / primaryParallelConn1_2R);
		Assert(primaryParallelConn1_3Gamma1 >= 0.0 && primaryParallelConn1_3Gamma1 <= 1.0);
		Real primaryInputSeriesConn_3R = (primarySeriesConn2_3R + primaryParallelConn1_3R);
		primaryInputSeriesConn_3Gamma1 = primarySeriesConn2_3R/(primarySeriesConn2_3R + primaryParallelConn1_3R);
		Assert(primaryInputSeriesConn_3Gamma1 >= 0.0 && primaryInputSeriesConn_3Gamma1 <= 1.0);
		Real parallelConn_3R = (primaryInputSeriesConn_3R + RinputTerminationR);
		parallelConn_3Gamma1 = primaryInputSeriesConn_3R/(primaryInputSeriesConn_3R + RinputTerminationR);
		Assert(parallelConn_3Gamma1 >= 0.0 && parallelConn_3Gamma1 <= 1.0);
		seriesConn_3Gamma1 = parallelConn_3R/(parallelConn_3R + inputSourceR);
		Assert(seriesConn_3Gamma1 >= 0.0 && seriesConn_3Gamma1 <= 1.0);
	}

	Real advance(Real vin){
		inputSourceE = vin;
		//Get Bs
		//seriesConn_3GetB
		//parallelConn_3GetB
		//primaryInputSeriesConn_3GetB
		//primarySeriesConn2_3GetB
		Real Lpb = -Lpa;
		//primarySeriesConn2_1SetA
		//RpGetB
		//primarySeriesConn2_2SetA
		Real primarySeriesConn2_3b3 = -(Lpb);
		//primaryInputSeriesConn_1SetA
		//primaryParallelConn1_3GetB
		//transformerGetB
		//secondarySeriesConn1_3GetB
		//secondaryOutputParallelConn_3GetB
		//RloadGetB
		//secondaryOutputParallelConn_1SetA
		Real Cwb = Cwa;
		//secondaryOutputParallelConn_2SetA
		Real secondaryOutputParallelConn_3b3 = Cwb - secondaryOutputParallelConn_3Gamma1*(Cwb);
		//secondarySeriesConn1_1SetA
		//secondarySeriesConn2_3GetB
		//RsGetB
		//secondarySeriesConn2_1SetA
		Real Lsb = -Lsa;
		//secondarySeriesConn2_2SetA
		Real secondarySeriesConn2_3b3 = -(Lsb);
		//secondarySeriesConn1_2SetA
		Real secondarySeriesConn1_3b3 = -(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3);
		//primaryParallelConn1_1SetA
		//primaryParallelConn2_3GetB
		Real Lmb = -Lma;
		//primaryParallelConn2_1SetA
		//RcGetB
		//primaryParallelConn2_2SetA
		Real primaryParallelConn2_3b3 = -primaryParallelConn2_3Gamma1*(-Lmb);
		//primaryParallelConn1_2SetA
		Real primaryParallelConn1_3b3 = primaryParallelConn2_3b3 - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
		//primaryInputSeriesConn_2SetA
		Real primaryInputSeriesConn_3b3 = -(primarySeriesConn2_3b3 + primaryParallelConn1_3b3);
		//parallelConn_1SetA
		//RinputTerminationGetB
		//parallelConn_2SetA
		Real parallelConn_3b3 = -(primaryInputSeriesConn_3b3);
		//seriesConn_1SetA
		//inputSourceGetB
		//seriesConn_2SetA
		Real seriesConn_3b3 = -(parallelConn_3b3 + inputSourceE);
		Real b = -(seriesConn_3b3);
		//Set As
		//seriesConn_3SetA
		Real seriesConn_3b1 = parallelConn_3b3 - seriesConn_3Gamma1*(parallelConn_3b3 + inputSourceE + b);
		//parallelConn_3SetA
		Real parallelConn_3b1 = primaryInputSeriesConn_3b3 - parallelConn_3Gamma1*(primaryInputSeriesConn_3b3 + seriesConn_3b1);
		//primaryInputSeriesConn_3SetA
		Real primaryInputSeriesConn_3b1 = primarySeriesConn2_3b3 - primaryInputSeriesConn_3Gamma1*(primarySeriesConn2_3b3 + primaryParallelConn1_3b3 + parallelConn_3b1);
		//primarySeriesConn2_3SetA
		Real primarySeriesConn2_3b1 = Lpb - primarySeriesConn2_3Gamma1*(Lpb + primaryInputSeriesConn_3b1);
		Lpa = primarySeriesConn2_3b1;
		//RpSetA
		Real primaryInputSeriesConn_3b2 = -(primarySeriesConn2_3b3 + parallelConn_3b1 - primaryInputSeriesConn_3Gamma1*(primarySeriesConn2_3b3 + primaryParallelConn1_3b3 + parallelConn_3b1));
		//primaryParallelConn1_3SetA
		Real primaryParallelConn1_3b1 = primaryInputSeriesConn_3b2 + primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
		//transformerSetA
		//secondarySeriesConn1_3SetA
		Real secondarySeriesConn1_3b1 = secondaryOutputParallelConn_3b3 - secondarySeriesConn1_3Gamma1*(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3 + primaryParallelConn1_3b1*transformern);
		//secondaryOutputParallelConn_3SetA
		//RloadSetA
		Real secondaryOutputParallelConn_3b2 = secondarySeriesConn1_3b1 - secondaryOutputParallelConn_3Gamma1*(Cwb);
		Cwa = secondaryOutputParallelConn_3b2;
		Real secondarySeriesConn1_3b2 = -(secondaryOutputParallelConn_3b3 + primaryParallelConn1_3b1*transformern - secondarySeriesConn1_3Gamma1*(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3 + primaryParallelConn1_3b1*transformern));
		//secondarySeriesConn2_3SetA
		//RsSetA
		Real secondarySeriesConn2_3b2 = -(secondarySeriesConn1_3b2 - secondarySeriesConn2_3Gamma1*(Lsb + secondarySeriesConn1_3b2));
		Lsa = secondarySeriesConn2_3b2;
		Real primaryParallelConn1_3b2 = primaryInputSeriesConn_3b2 - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
		//primaryParallelConn2_3SetA
		Real primaryParallelConn2_3b1 = primaryParallelConn1_3b2  - Lmb - primaryParallelConn2_3Gamma1*(-Lmb);
		Lma = primaryParallelConn2_3b1;
		//RcSetA
		//RinputTerminationSetA
		return -(Cwa + Cwb);
	}

	vector<Real> getState(){
		vector<Real> state(4, 0.0);
		state[0] = Lpa;
		state[1] = Lma;
		state[2] = Lsa;
		state[3] = Cwa;
		return state;
	}
	void setState(vector<Real> state) {
		Assert(state.size() == 4);
		Lpa = state[0];
		Lma = state[1];
		Lsa = state[2];
		Cwa = state[3];
	}
private:
	//State variables
	Real Lpa;
	Real Lma;
	Real Lsa;
	Real Cwa;

	//R values
	Real primarySeriesConn2_3Gamma1;
	Real seriesConn_3Gamma1;
	Real secondarySeriesConn2_3Gamma1;
	Real primaryInputSeriesConn_3Gamma1;
	Real parallelConn_3Gamma1;
	Real secondaryOutputParallelConn_3Gamma1;
	Real secondarySeriesConn1_3Gamma1;
	Real transformerOneOvern;
	Real inputSourceE;
	Real transformern;
	Real primaryParallelConn2_3Gamma1;
	Real primaryParallelConn1_3Gamma1;
	//Extra members
};



// AUTOGENERATED Wave digital filter 2012-03-14 15:24:51.156199
// Advanced Machine Audio Python WDF Generator 
// Peter Raffensperger, 2012
class LevelTimeConstantCircuit {
	/*Circuit schematic:
	 --------------------------
	 |       |    |     |     |
	 |       |    |     R2    R3
	Iin      R1   C1    |     |
	 |       |    |     C2    C3
	 |       |    |     |     |
	 --------------------------
	*/
public:
	LevelTimeConstantCircuit(Real C_C1, Real C_C2, Real C_C3, Real R_R1, Real R_R2, Real R_R3, Real sampleRate){
		updateRValues(C_C1, C_C2, C_C3, R_R1, R_R2, R_R3, sampleRate);
		C1a = 0.0;
		C2a = 0.0;
		C3a = 0.0;
	}

	void updateRValues(Real C_C1, Real C_C2, Real C_C3, Real R_R1, Real R_R2, Real R_R3, Real sampleRate){
		Real R1R = R_R1;
		Real C1R = 1.0 / (2.0*C_C1*sampleRate);
		Real R2R = R_R2;
		Real C2R = 1.0 / (2.0*C_C2*sampleRate);
		Real R3R = R_R3;
		Real C3R = 1.0 / (2.0*C_C3*sampleRate);
		Real serialConn2_3R = (R2R + C2R);
		serialConn2_3Gamma1 = R2R/(R2R + C2R);
		Assert(serialConn2_3Gamma1 >= 0.0 && serialConn2_3Gamma1 <= 1.0);
		Real serialConn3_3R = (R3R + C3R);
		serialConn3_3Gamma1 = R3R/(R3R + C3R);
		Assert(serialConn3_3Gamma1 >= 0.0 && serialConn3_3Gamma1 <= 1.0);
		Real parallelConn23_1R = serialConn2_3R;
		Real parallelConn23_2R = serialConn3_3R;
		Real parallelConn23_3R = 1.0 /(1.0 / parallelConn23_1R + 1.0 / parallelConn23_2R);
		parallelConn23_3Gamma1 = 1.0 / parallelConn23_1R/(1.0 / parallelConn23_1R + 1.0 / parallelConn23_2R);
		Assert(parallelConn23_3Gamma1 >= 0.0 && parallelConn23_3Gamma1 <= 1.0);
		Real parallelConn1_1R = R1R;
		Real parallelConn1_2R = C1R;
		Real parallelConn1_3R = 1.0 /(1.0 / parallelConn1_1R + 1.0 / parallelConn1_2R);
		parallelConn1_3Gamma1 = 1.0 / parallelConn1_1R/(1.0 / parallelConn1_1R + 1.0 / parallelConn1_2R);
		Assert(parallelConn1_3Gamma1 >= 0.0 && parallelConn1_3Gamma1 <= 1.0);
		Real parallelConnInput_1R = parallelConn1_3R;
		Real parallelConnInput_2R = parallelConn23_3R;
		Real parallelConnInput_3R = 1.0 /(1.0 / parallelConnInput_1R + 1.0 / parallelConnInput_2R);
		parallelConnInput_3Gamma1 = 1.0 / parallelConnInput_1R/(1.0 / parallelConnInput_1R + 1.0 / parallelConnInput_2R);
		Assert(parallelConnInput_3Gamma1 >= 0.0 && parallelConnInput_3Gamma1 <= 1.0);
		Rsource = parallelConnInput_3R;
	}

	Real advance(Real Iin){
		//parallelConnInput_3GetB
		//parallelConn1_3GetB
		//R1GetB
		//parallelConn1_1SetA
		Real C1b = C1a;
		//parallelConn1_2SetA
		Real parallelConn1_3b3 = C1b - parallelConn1_3Gamma1*(C1b);
		//parallelConnInput_1SetA
		//parallelConn23_3GetB
		//serialConn2_3GetB
		//R2GetB
		//serialConn2_1SetA
		Real C2b = C2a;
		//serialConn2_2SetA
		Real serialConn2_3b3 = -(C2b);
		//parallelConn23_1SetA
		//serialConn3_3GetB
		//R3GetB
		//serialConn3_1SetA
		Real C3b = C3a;
		//serialConn3_2SetA
		Real serialConn3_3b3 = -(C3b);
		//parallelConn23_2SetA
		Real parallelConn23_3b3 = serialConn3_3b3 - parallelConn23_3Gamma1*(serialConn3_3b3 - serialConn2_3b3);
		//parallelConnInput_2SetA
		Real parallelConnInput_3b3 = parallelConn23_3b3 - parallelConnInput_3Gamma1*(parallelConn23_3b3 - parallelConn1_3b3);
		//Current source law
		Real e = Iin * Rsource;
		Real b = (parallelConnInput_3b3) - 2.0*e;
		//parallelConnInput_3SetA
		Real parallelConnInput_3b1 = b + parallelConn23_3b3 - parallelConn1_3b3 - parallelConnInput_3Gamma1*(parallelConn23_3b3 - parallelConn1_3b3);
		//parallelConn1_3SetA
		//R1SetA
		Real parallelConn1_3b2 = parallelConnInput_3b1 - parallelConn1_3Gamma1*(C1b);
		C1a = parallelConn1_3b2;
		Real parallelConnInput_3b2 = b - parallelConnInput_3Gamma1*(parallelConn23_3b3 - parallelConn1_3b3);
		//parallelConn23_3SetA
		Real parallelConn23_3b1 = parallelConnInput_3b2 + serialConn3_3b3 - serialConn2_3b3 - parallelConn23_3Gamma1*(serialConn3_3b3 - serialConn2_3b3);
		//serialConn2_3SetA
		//R2SetA
		Real serialConn2_3b2 = -(parallelConn23_3b1 - serialConn2_3Gamma1*(C2b + parallelConn23_3b1));
		C2a = serialConn2_3b2;
		Real parallelConn23_3b2 = parallelConnInput_3b2 - parallelConn23_3Gamma1*(serialConn3_3b3 - serialConn2_3b3);
		//serialConn3_3SetA
		//R3SetA
		Real serialConn3_3b2 = -(parallelConn23_3b2 - serialConn3_3Gamma1*(C3b + parallelConn23_3b2));
		C3a = serialConn3_3b2;
		return -(C1a + C1b);
	}

	vector<Real> getState(){
		vector<Real> state(3, 0.0);
		state[0] = C1a;
		state[1] = C2a;
		state[2] = C3a;
		return state;
	}
	void setState(vector<Real> state) {
		Assert(state.size() == 3);
		C1a = state[0];
		C2a = state[1];
		C3a = state[2];
	}
private:
	//State variables
	Real C1a;
	Real C2a;
	Real C3a;

	//R values
	Real serialConn2_3Gamma1;
	Real Rsource;
	Real parallelConn1_3Gamma1;
	Real serialConn3_3Gamma1;
	Real parallelConnInput_3Gamma1;
	Real parallelConn23_3Gamma1;
	//Extra members
};




#endif

